﻿#region Copyright Jonathan Quiros

//	
// All rights are reserved. Reproduction or transmission in whole or in 
// part, in any form or by any means, electronic, mechanical or otherwise, 
// is prohibited without the prior written consent of the copyright owner.
//
// Filename: ListHelper.cs
//

#endregion

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Web.Mvc;
using Novagoal.Website.WebApp.Controllers;
using Novagoal.Website.WebApp.Routing;
using Ids.Utils;
using Ids.Web.Listing;
using System.Web.Routing;

namespace Novagoal.Website.WebApp.Helpers
{
    public static class ListHelper
    {
        #region Constants
        const string TEXTBOX_FORMAT = "<input type=\"text\" id=\"{0}\" name=\"{0}\" value=\"{1}\" onchange=\"javascript:filterList();\" {2}/>";
        const string SELECT_OPEN_FORMAT = "<select id=\"{0}\" name=\"{0}\" onchange=\"javascript:filterList();\">";
        const string SELECT_ITEM_FORMAT = "<option value=\"{0}\">{1}</option>";
        const string SELECT_ITEM_SEL_FORMAT = "<option value=\"{0}\" selected=\"selected\">{1}</option>";
        const string SELECT_CLOSE_FORMAT = "</select>";
        const string SELECT_PAGE_SIZE_OPEN = "<div class=\"{0}\">View: <select id=\"{0}\" name=\"{0}\" onchange=\"javascript:filterList();\">";
        const string SELECT_PAGE_SIZE_CLOSE = "</select></div>";
        const string VALUE = "{0} per page";
        const string PAGE_SIZE = "page_size";
        #endregion

        #region Public Methods

        public static MvcHtmlString CellAction(int id, string fieldName, string text)
        {

            var actionBuilder = new StringBuilder("javascript:editProperty(");
            actionBuilder.Append(id);
            actionBuilder.Append(", '" + fieldName);
            actionBuilder.Append("', '" + text);
            actionBuilder.Append("')");

            var strBuilder = new StringBuilder();

            strBuilder.AppendFormat("<td class='editable-cell' onclick='{0}'><span>{1}</span></td>", actionBuilder.ToString(), text);

            return MvcHtmlString.Create(strBuilder.ToString());
        }

        /// <summary>
        /// Sorts the action.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="wrapper">The wrapper.</param>
        /// <param name="text">The text.</param>
        /// <param name="sortField">The sort field.</param>
        /// <returns></returns>
        public static MvcHtmlString SortAction(UrlHelper url, ListWrapper wrapper, string text, object sortField)
        {
            var actionName = url.RequestContext.RouteData.Values["action"].ToString();
            return SortAction(url, actionName, wrapper, text, sortField);
        }

        /// <summary>
        /// Sorts the specified page.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="actionName">Name of the action.</param>
        /// <param name="wrapper">The wrapper.</param>
        /// <param name="text">The text.</param>
        /// <param name="sortField">The sort field.</param>
        /// <returns></returns>
        public static MvcHtmlString SortAction(UrlHelper url, string actionName, ListWrapper wrapper, string text, object sortField)
        {
            StringBuilder strBuilder = new StringBuilder();
            strBuilder.AppendFormat("<a href=\"{0}\">{1}</a>", url.RouteUrl(wrapper.GetSortRouteValues(sortField, actionName)), text);
            if (wrapper.SortField.Equals(sortField))
            {
                strBuilder.Insert(0, "&nbsp;");
                const string strIcon = "&nbsp;<span class=\"icon ui-icon ui-icon-triangle-1-{0}\"></span>";
                if (wrapper.SortDirection == SortDirectionType.Ascending)
                    strBuilder.AppendFormat(strIcon, "n");
                else
                    strBuilder.AppendFormat(strIcon, "s");
            }

            return MvcHtmlString.Create(strBuilder.ToString());
        }

        /// <summary>
        /// Creates Paging Control for the specified model.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="wrapper">The wrapper.</param>
        /// <returns></returns>
        public static MvcHtmlString Paging(UrlHelper url, ListWrapper wrapper)
        {
            var actionName = url.RequestContext.RouteData.Values["action"].ToString();
            return Paging(url, actionName, wrapper);
        }

        /// <summary>
        /// Pagings the specified URL.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <param name="actionName">Name of the action.</param>
        /// <param name="wrapper">The wrapper.</param>
        /// <returns></returns>
        public static MvcHtmlString Paging(UrlHelper url, string actionName, ListWrapper wrapper)
        {
            int pagingBlock = ListController.PagingBlock;

            Func<int, string> createPageLink;
            if (!string.IsNullOrEmpty(actionName))
            {
                createPageLink = page => url.Action(actionName, wrapper.GetPageRouteValues(pagingBlock, page));
            }
            else
            {
                createPageLink = page => url.RouteUrl(wrapper.GetPageRouteValues(pagingBlock, page));
            }

            return Paging(createPageLink, wrapper, pagingBlock);
        }

        /// <summary>
        /// Pagings the specified link format.
        /// </summary>
        /// <param name="linkFormat">The link format.</param>
        /// <param name="wrapper">The wrapper.</param>
        /// <returns></returns>
        public static MvcHtmlString Paging(string linkFormat, IPagingModel wrapper)
        {
            Func<int, string> createPageLink = page => string.Format(linkFormat, page);
            return Paging(createPageLink, wrapper, ListController.PagingBlock);
        }

        /// <summary>
        /// Creates Paging Control for the specified model.
        /// </summary>
        /// <param name="createPageLink">A function to create a link from a page provided.</param>
        /// <param name="wrapper">The wrapper.</param>
        /// <param name="pagingBlock">The paging block.</param>
        /// <returns></returns>
        private static MvcHtmlString Paging(Func<int, string> createPageLink, IPagingModel wrapper, int pagingBlock)
        {
            const string strFormat = "<li class='button ui-state-default ui-corner-all' onclick='javascript:window.location.href=\"{0}\"'><span>{1}</span></li>";
            const string strActive = "<li class='button ui-state-highlight ui-state-default ui-corner-all ui-state-hover'><span>{0}</span></li>";
            const string spanNext = "<span class=\"icon ui-icon ui-icon-triangle-1-e\"></span>";
            const string spanPrevious = "<span class=\"icon ui-icon ui-icon-triangle-1-w\"></span>";
            const string separator = "<li>...</li>";

            int nextpage = wrapper.CurrentPage + 1;
            if (nextpage > wrapper.TotalPages) nextpage = -1;

            int previousPage = wrapper.CurrentPage - 1;
            if (previousPage < 1) previousPage = -1;

            int startPage = wrapper.CurrentPage - (pagingBlock / 2);
            if (startPage <= 0 || wrapper.TotalPages <= pagingBlock)
                startPage = 1;

            int lastpage = startPage + pagingBlock - 1;
            if (lastpage > wrapper.TotalPages)
                lastpage = wrapper.TotalPages;

            StringBuilder strBuilder = new StringBuilder();
            strBuilder.Append("<ul>");

            if (previousPage > 0)
                strBuilder.AppendFormat(strFormat, createPageLink(previousPage), spanPrevious);

            if (startPage != 1)
                strBuilder.AppendFormat(strFormat + separator, createPageLink(1), 1);

            for (int page = startPage; page <= lastpage; page++)
            {
                if (page == wrapper.CurrentPage)
                    strBuilder.AppendFormat(strActive, page);
                else
                    strBuilder.AppendFormat(strFormat, createPageLink(page), page);
            }

            if (lastpage != wrapper.TotalPages)
                strBuilder.AppendFormat(separator + strFormat, createPageLink(wrapper.TotalPages), wrapper.TotalPages);

            if (nextpage > 0)
                strBuilder.AppendFormat(strFormat, createPageLink(nextpage), spanNext);

            strBuilder.Append("</ul>");

            return MvcHtmlString.Create(strBuilder.ToString());
        }

        /// <summary>
        /// Totals the items.
        /// </summary>
        /// <param name="quantity"></param>
        /// <param name="label"></param>
        /// <returns></returns>
        public static MvcHtmlString TotalItems(int quantity, string label)
        {
            string spanTotal = string.Format("<span class=\"total-items\">{0} {1}</span>", quantity, label);
            return MvcHtmlString.Create(spanTotal);
        }

        /// <summary>
        /// Totals the items.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        public static MvcHtmlString CurrentPage(IPagingModel model)
        {
            string spanTotal = string.Format("<span class=\"labels-left\">Page #{0}</span>", model.CurrentPage);
            return MvcHtmlString.Create(spanTotal);
        }

        /// <summary>
        /// Drops down list for.
        /// </summary>
        /// <param name="wrapper">The wrapper.</param>
        /// <param name="filterField">The filter field.</param>
        /// <param name="values">The values.</param>
        /// <param name="selectLabel">The select label.</param>
        /// <returns></returns>
        public static MvcHtmlString DropDownListFor(ListWrapper wrapper, object filterField, List<ListFilterValue> values, string selectLabel)
        {
            string value = GetFilterValue(wrapper, filterField);
            StringBuilder strBuilder = new StringBuilder();
            strBuilder.AppendFormat(SELECT_OPEN_FORMAT, filterField.ToStringValue());

            if (!string.IsNullOrEmpty(selectLabel))
                strBuilder.AppendFormat(SELECT_ITEM_FORMAT, string.Empty, selectLabel);

            foreach (var item in values)
            {
                if (!string.IsNullOrEmpty(value) && item.Value.Equals(value))
                    strBuilder.AppendFormat(SELECT_ITEM_SEL_FORMAT, item.Value, item.Name);
                else
                    strBuilder.AppendFormat(SELECT_ITEM_FORMAT, item.Value, item.Name);
            }
            strBuilder.Append(SELECT_CLOSE_FORMAT);

            return MvcHtmlString.Create(strBuilder.ToString());
        }

        /// <summary>
        /// Drops down list for boolean.
        /// </summary>
        /// <param name="wrapper">The wrapper.</param>
        /// <param name="filterField">The filter field.</param>
        /// <param name="trueLabel">The true label.</param>
        /// <param name="falseLabel">The false label.</param>
        /// <param name="selectLabel">The select label.</param>
        /// <returns></returns>
        public static MvcHtmlString DropDownListForBoolean(ListWrapper wrapper, object filterField, string trueLabel, string falseLabel, string selectLabel)
        {
            List<ListFilterValue> values = new List<ListFilterValue>
                                               {
                                                   new ListFilterValue(trueLabel, "true"),
                                                   new ListFilterValue(falseLabel, "false")
                                               };
            return DropDownListFor(wrapper, filterField, values, selectLabel);
        }

        public static MvcHtmlString DropDownListForPaging(this HtmlHelper htmlHelper, int quantityItems, int lapsesOf, RouteValueDictionary routeValuesDictionary)
        {
            var controller = htmlHelper.ViewContext.Controller;
            var initialPosition = (controller is BaseController)
                                      ? (controller as BaseController).ApplicationSettings.PageSize
                                      : 0;

            return DropDownListForPaging(initialPosition, quantityItems, lapsesOf, routeValuesDictionary);
        }

        public static MvcHtmlString DropDownListForPaging(int initialPosition, int quantityItems, int lapsesOf, RouteValueDictionary routeValues)
        {
            //var initialPosition = Convert.ToInt32(ConfigurationManager.AppSettings[PAGE_SIZE]);
            var selectedValue = routeValues.ContainsKey(PAGE_SIZE) ? Convert.ToString(routeValues[PAGE_SIZE]) : string.Empty;
            return DropDownListForPaging(initialPosition, selectedValue, quantityItems, lapsesOf);
        }

        private static MvcHtmlString DropDownListForPaging(int initialPosition, string selectedValue, int quantityItems, int lapsesOf)
        {
            var values = new List<ListFilterValue>();
            for (int i = 0; i < quantityItems; i++)
            {
                var value = Convert.ToString(initialPosition + ((i * lapsesOf) * i));
                values.Add(new ListFilterValue(new StringBuilder().AppendFormat(VALUE, value).ToString(), value));
            }

            return DropDownListForPaging(PAGE_SIZE, selectedValue, values, Convert.ToString(initialPosition));
        }

        private static MvcHtmlString DropDownListForPaging(string name, string selectedValue, List<ListFilterValue> values, string selectLabel)
        {
            var strBuilder = new StringBuilder();
            strBuilder.AppendFormat(SELECT_PAGE_SIZE_OPEN, name);

            for (int i = 0; i < values.Count; i++)
            {
                if (!string.IsNullOrEmpty(selectedValue) && values[i].Value.Equals(selectedValue))
                    strBuilder.AppendFormat(SELECT_ITEM_SEL_FORMAT, values[i].Value, values[i].Name);
                else
                    strBuilder.AppendFormat(SELECT_ITEM_FORMAT, values[i].Value, values[i].Name);
            }
            strBuilder.Append(SELECT_PAGE_SIZE_CLOSE);

            return MvcHtmlString.Create(strBuilder.ToString());
        }

        /// <summary>
        /// Generates the textbox.
        /// </summary>
        /// <param name="wrapper">The wrapper.</param>
        /// <param name="filterField">The filter field.</param>
        /// <param name="attributes">The attributes.</param>
        /// <returns></returns>
        public static MvcHtmlString TextBoxFor(ListWrapper wrapper, object filterField, string attributes)
        {
            string value = GetFilterValue(wrapper, filterField);
            string strTextbox = string.Format(TEXTBOX_FORMAT, filterField.ToStringValue(), value, attributes);
            return MvcHtmlString.Create(strTextbox);
        }

        /// <summary>
        /// Texts the box for.
        /// </summary>
        /// <param name="wrapper">The wrapper.</param>
        /// <param name="filterField">The filter field.</param>
        /// <returns></returns>
        public static MvcHtmlString TextBoxFor(ListWrapper wrapper, object filterField)
        {
            return TextBoxFor(wrapper, filterField, null);
        }
        #endregion

        #region Private Methods
        /// <summary>
        /// Gets the filter value.
        /// </summary>
        /// <param name="wrapper">The wrapper.</param>
        /// <param name="filterField">The filter field.</param>
        /// <returns></returns>
        private static string GetFilterValue(ListWrapper wrapper, object filterField)
        {
            IDictionary filters = wrapper.Filters;
            string value = string.Empty;
            if (filters != null && filters[filterField] != null)
                value = filters[filterField].ToString();

            return value;
        }
        #endregion
    }
}